Merge "Use short assignment operator in PHP"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Thu, 7 Mar 2019 20:52:45 +0000 (20:52 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Thu, 7 Mar 2019 20:52:45 +0000 (20:52 +0000)
20 files changed:
includes/api/ApiQueryAllUsers.php
includes/api/ApiQueryContributors.php
includes/clientpool/SquidPurgeClient.php
includes/http/Http.php
includes/libs/filebackend/FileBackendStore.php
includes/specials/SpecialUploadStash.php
includes/upload/UploadBase.php
includes/user/User.php
maintenance/categoryChangesAsRdf.php
maintenance/cleanupInvalidDbKeys.php
maintenance/cleanupTable.inc
maintenance/cleanupUsersWithNoId.php
maintenance/convertExtensionToRegistration.php
maintenance/copyFileBackend.php
maintenance/deleteOrphanedRevisions.php
maintenance/dumpCategoriesAsRdf.php
maintenance/dumpUploads.php
maintenance/generateJsonI18n.php
maintenance/orphans.php
tests/phpunit/includes/user/UserTest.php

index d7adb9b..8b3d864 100644 (file)
@@ -141,7 +141,7 @@ class ApiQueryAllUsers extends ApiQueryBase {
                                        LIST_OR
                                ) ];
                        }
-                       $this->addJoinConds( [ 'ug1' => [ 'LEFT OUTER JOIN',
+                       $this->addJoinConds( [ 'ug1' => [ 'LEFT JOIN',
                                array_merge( [
                                        'ug1.ug_user=user_id',
                                        'ug1.ug_expiry IS NULL OR ug1.ug_expiry >= ' . $db->addQuotes( $db->timestamp() )
index 93cf016..9057f10 100644 (file)
@@ -176,7 +176,7 @@ class ApiQueryContributors extends ApiQueryBase {
                        $limitGroups = array_unique( $limitGroups );
                        $this->addTables( 'user_groups' );
                        $this->addJoinConds( [ 'user_groups' => [
-                               $excludeGroups ? 'LEFT OUTER JOIN' : 'JOIN',
+                               $excludeGroups ? 'LEFT JOIN' : 'JOIN',
                                [
                                        'ug_user=' . $revQuery['fields']['rev_user'],
                                        'ug_group' => $limitGroups,
index 005b326..49d9d1c 100644 (file)
@@ -25,7 +25,7 @@
  * Uses asynchronous I/O, allowing purges to be done in a highly parallel
  * manner.
  *
- * Could be replaced by curl_multi_exec() or some such.
+ * @todo Consider using MultiHttpClient.
  */
 class SquidPurgeClient {
        /** @var string */
index c29f199..f0972dc 100644 (file)
@@ -132,11 +132,14 @@ class Http {
        }
 
        /**
-        * Checks that the given URI is a valid one. Hardcoding the
-        * protocols, because we only want protocols that both cURL
-        * and php support.
+        * Check that the given URI is a valid one.
         *
-        * file:// should not be allowed here for security purpose (r67684)
+        * This hardcodes a small set of protocols only, because we want to
+        * deterministically reject protocols not supported by all HTTP-transport
+        * methods.
+        *
+        * "file://" specifically must not be allowed, for security purpose
+        * (see <https://www.mediawiki.org/wiki/Special:Code/MediaWiki/r67684>).
         *
         * @todo FIXME this is wildly inaccurate and fails to actually check most stuff
         *
index 28a293f..97da557 100644 (file)
@@ -1009,7 +1009,7 @@ abstract class FileBackendStore extends FileBackend {
         * @param string $container Resolved container name
         * @param string $dir Resolved path relative to container
         * @param array $params
-        * @return Traversable|array|null Returns null on failure
+        * @return Traversable|string[]|null Returns null on failure
         */
        abstract public function getFileListInternal( $container, $dir, array $params );
 
index abd3e07..4d0c20c 100644 (file)
@@ -261,7 +261,8 @@ class SpecialUploadStash extends UnlistedSpecialPage {
                $scalerThumbUrl = $scalerBaseUrl . '/' . $file->getUrlRel() .
                        '/' . rawurlencode( $scalerThumbName );
 
-               // make a curl call to the scaler to create a thumbnail
+               // make an http request based on wgUploadStashScalerBaseUrl to lazy-create
+               // a thumbnail
                $httpOptions = [
                        'method' => 'GET',
                        'timeout' => 5 // T90599 attempt to time out cleanly
index d9e8e99..c42584c 100644 (file)
@@ -1169,7 +1169,7 @@ abstract class UploadBase {
         * scripts, so the blacklist needs to check them all.
         *
         * @param string $filename
-        * @return array
+        * @return array [ string, string[] ]
         */
        public static function splitExtensions( $filename ) {
                $bits = explode( '.', $filename );
@@ -1194,8 +1194,8 @@ abstract class UploadBase {
         * Perform case-insensitive match against a list of file extensions.
         * Returns an array of matching extensions.
         *
-        * @param array $ext
-        * @param array $list
+        * @param string[] $ext
+        * @param string[] $list
         * @return bool
         */
        public static function checkFileExtensionList( $ext, $list ) {
index 1e3ecf2..f84a6ff 100644 (file)
@@ -4974,6 +4974,28 @@ class User implements IDBAccessObject, UserIdentity {
         *  non-existent/anonymous user accounts.
         */
        public function getFirstEditTimestamp() {
+               return $this->getEditTimestamp( true );
+       }
+
+       /**
+        * Get the timestamp of the latest edit
+        *
+        * @since 1.33
+        * @return string|bool Timestamp of first edit, or false for
+        *  non-existent/anonymous user accounts.
+        */
+       public function getLatestEditTimestamp() {
+               return $this->getEditTimestamp( false );
+       }
+
+       /**
+        * Get the timestamp of the first or latest edit
+        *
+        * @param bool $first True for the first edit, false for the latest one
+        * @return string|bool Timestamp of first or latest edit, or false for
+        *  non-existent/anonymous user accounts.
+        */
+       private function getEditTimestamp( $first ) {
                if ( $this->getId() == 0 ) {
                        return false; // anons
                }
@@ -4981,12 +5003,13 @@ class User implements IDBAccessObject, UserIdentity {
                $actorWhere = ActorMigration::newMigration()->getWhere( $dbr, 'rev_user', $this );
                $tsField = isset( $actorWhere['tables']['temp_rev_user'] )
                        ? 'revactor_timestamp' : 'rev_timestamp';
+               $sortOrder = $first ? 'ASC' : 'DESC';
                $time = $dbr->selectField(
                        [ 'revision' ] + $actorWhere['tables'],
                        $tsField,
                        [ $actorWhere['conds'] ],
                        __METHOD__,
-                       [ 'ORDER BY' => "$tsField ASC" ],
+                       [ 'ORDER BY' => "$tsField $sortOrder" ],
                        $actorWhere['joins']
                );
                if ( !$time ) {
index 8324133..1d85dcc 100644 (file)
@@ -402,7 +402,7 @@ SPARQL;
        /**
         * Get iterator for links for categories.
         * @param IDatabase $dbr
-        * @param array $ids List of page IDs
+        * @param int[] $ids List of page IDs
         * @return Traversable
         */
        protected function getCategoryLinksIterator( IDatabase $dbr, array $ids ) {
index a1820b8..abae4f4 100644 (file)
@@ -30,7 +30,7 @@ require_once __DIR__ . '/Maintenance.php';
  * @ingroup Maintenance
  */
 class CleanupInvalidDbKeys extends Maintenance {
-       /** @var array List of tables to clean up, and the field prefix for that table */
+       /** @var array[] List of tables to clean up, and the field prefix for that table */
        protected static $tables = [
                // Data tables
                [ 'page', 'page' ],
index 3ace09c..b78e691 100644 (file)
@@ -165,7 +165,7 @@ class TableCleanup extends Maintenance {
        }
 
        /**
-        * @param array $matches
+        * @param string[] $matches
         * @return string
         */
        protected function hexChar( $matches ) {
index b2fdf2f..61d1e5d 100644 (file)
@@ -95,7 +95,7 @@ class CleanupUsersWithNoId extends LoggedUpdateMaintenance {
         * @param IDatabase $dbw
         * @param string[] $indexFields Fields in the index being ordered by
         * @param object $row Database row
-        * @return array [ string $next, string $display ]
+        * @return string[] [ string $next, string $display ]
         */
        private function makeNextCond( $dbw, $indexFields, $row ) {
                $next = '';
index 6c1edc2..a09ca5c 100644 (file)
@@ -19,7 +19,7 @@ class ConvertExtensionToRegistration extends Maintenance {
        /**
         * Things that were formerly globals and should still be converted
         *
-        * @var array
+        * @var string[]
         */
        protected $formerGlobals = [
                'TrackingCategories',
@@ -28,7 +28,7 @@ class ConvertExtensionToRegistration extends Maintenance {
        /**
         * No longer supported globals (with reason) should not be converted and emit a warning
         *
-        * @var array
+        * @var string[]
         */
        protected $noLongerSupportedGlobals = [
                'SpecialPageGroups' => 'deprecated', // Deprecated 1.21, removed in 1.26
@@ -37,7 +37,7 @@ class ConvertExtensionToRegistration extends Maintenance {
        /**
         * Keys that should be put at the top of the generated JSON file (T86608)
         *
-        * @var array
+        * @var string[]
         */
        protected $promote = [
                'name',
index 3374893..9ba5bf5 100644 (file)
@@ -168,7 +168,7 @@ class CopyFileBackend extends Maintenance {
         * @param FileBackend $src
         * @param FileBackend $dst
         * @param string $backendRel
-        * @return array (rel paths in $src minus those in $dst)
+        * @return string[] (rel paths in $src minus those in $dst)
         */
        protected function getListingDiffRel( FileBackend $src, FileBackend $dst, $backendRel ) {
                $srcPathsRel = $src->getFileList( [
@@ -200,7 +200,7 @@ class CopyFileBackend extends Maintenance {
        }
 
        /**
-        * @param array $srcPathsRel
+        * @param string[] $srcPathsRel
         * @param string $backendRel
         * @param FileBackend $src
         * @param FileBackend $dst
@@ -288,7 +288,7 @@ class CopyFileBackend extends Maintenance {
        }
 
        /**
-        * @param array $dstPathsRel
+        * @param string[] $dstPathsRel
         * @param string $backendRel
         * @param FileBackend $dst
         * @return void
index 8d3f6b3..6f3ea4c 100644 (file)
@@ -84,13 +84,10 @@ class DeleteOrphanedRevisions extends Maintenance {
         * Delete one or more revisions from the database
         * Do this inside a transaction
         *
-        * @param array $id Array of revision id values
+        * @param int[] $id Array of revision id values
         * @param IDatabase $dbw Master DB handle
         */
-       private function deleteRevs( $id, &$dbw ) {
-               if ( !is_array( $id ) ) {
-                       $id = [ $id ];
-               }
+       private function deleteRevs( array $id, &$dbw ) {
                $dbw->delete( 'revision', [ 'rev_id' => $id ], __METHOD__ );
 
                // Delete from ip_changes should a record exist.
index e4bd756..873d628 100644 (file)
@@ -90,7 +90,7 @@ class DumpCategoriesAsRdf extends Maintenance {
        /**
         * Get iterator for links for categories.
         * @param IDatabase $dbr
-        * @param array $ids List of page IDs
+        * @param int[] $ids List of page IDs
         * @return Traversable
         */
        public function getCategoryLinksIterator( IDatabase $dbr, array $ids ) {
index b4df20f..a5bc6cc 100644 (file)
@@ -82,7 +82,7 @@ By default, outputs relative paths against the parent directory of $wgUploadDire
 
                $sql = "SELECT DISTINCT il_to, img_name
                        FROM $imagelinks
-                       LEFT OUTER JOIN $image
+                       LEFT JOIN $image
                        ON il_to=img_name";
                $result = $dbr->query( $sql );
 
index efddfb3..a7224b4 100644 (file)
@@ -182,7 +182,7 @@ class GenerateJsonI18n extends Maintenance {
        /**
         * Get an array of author names from a documentation comment containing @author declarations.
         * @param string $comment Documentation comment
-        * @return array Array of author names (strings)
+        * @return string[] Array of author names
         */
        protected function getAuthorsFromComment( $comment ) {
                $matches = null;
index bfae4b7..e13468e 100644 (file)
@@ -154,7 +154,7 @@ class Orphans extends Maintenance {
                        . "(this may take a while on a large wiki)\n" );
                $result = $dbw->query( "
                        SELECT *
-                       FROM $page LEFT OUTER JOIN $revision ON page_latest=rev_id
+                       FROM $page LEFT JOIN $revision ON page_latest=rev_id
                " );
                $found = 0;
                foreach ( $result as $row ) {
index 64bdf31..dad7bf2 100644 (file)
@@ -1462,4 +1462,38 @@ class UserTest extends MediaWikiTestCase {
                // clean up
                $block->delete();
        }
+
+       /**
+        * @covers User::getFirstEditTimestamp
+        * @covers User::getLatestEditTimestamp
+        */
+       public function testGetFirstLatestEditTimestamp() {
+               $clock = MWTimestamp::convert( TS_UNIX, '20100101000000' );
+               MWTimestamp::setFakeTime( function () use ( &$clock ) {
+                       return $clock += 1000;
+               } );
+               $user = $this->getTestUser()->getUser();
+               $firstRevision = self::makeEdit( $user, 'Help:UserTest_GetEditTimestamp', 'one', 'test' );
+               $secondRevision = self::makeEdit( $user, 'Help:UserTest_GetEditTimestamp', 'two', 'test' );
+               // Sanity check: revisions timestamp are different
+               $this->assertNotEquals( $firstRevision->getTimestamp(), $secondRevision->getTimestamp() );
+
+               $this->assertEquals( $firstRevision->getTimestamp(), $user->getFirstEditTimestamp() );
+               $this->assertEquals( $secondRevision->getTimestamp(), $user->getLatestEditTimestamp() );
+       }
+
+       /**
+        * @param User $user
+        * @param string $title
+        * @param string $content
+        * @param string $comment
+        * @return \MediaWiki\Revision\RevisionRecord|null
+        */
+       private static function makeEdit( User $user, $title, $content, $comment ) {
+               $page = WikiPage::factory( Title::newFromText( $title ) );
+               $content = ContentHandler::makeContent( $content, $page->getTitle() );
+               $updater = $page->newPageUpdater( $user );
+               $updater->setContent( 'main', $content );
+               return $updater->saveRevision( CommentStoreComment::newUnsavedComment( $comment ) );
+       }
 }